{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Functional API implementation of a two-input question-answering model (7.1)\n",
    "2 input 1 output "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "from keras.models import Model\n",
    "from keras import layers, Input"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "text_vocabulary_size = 10000\n",
    "question_vocabulary_size = 10000\n",
    "answer_vocabulary_size = 500"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 1st input\n",
    "text_input = Input(shape=(None,), dtype='int32', name='text')\n",
    "embedded_text = layers.Embedding(text_vocabulary_size, 64)(text_input)\n",
    "encoded_text = layers.LSTM(32)(embedded_text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 2nd input\n",
    "question_input = Input(shape=(None,),dtype='int32',name='question')\n",
    "embedded_question = layers.Embedding(question_vocabulary_size, 32)(question_input)\n",
    "encoded_question = layers.LSTM(16)(embedded_question)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Concatenate both input and pass last output layer\n",
    "concatenated = layers.concatenate([encoded_text, encoded_question],axis=-1)\n",
    "\n",
    "answer = layers.Dense(answer_vocabulary_size,activation='softmax')(concatenated)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "model = Model([text_input, question_input], answer)\n",
    "\n",
    "model.compile(optimizer='rmsprop',loss='categorical_crossentropy',metrics=['acc'])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Feeding data to a multi-input model\n",
    "Genrating fake data"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "\n",
    "num_samples = 1000\n",
    "max_length = 100\n",
    "\n",
    "text = np.random.randint(1, text_vocabulary_size,size=(num_samples, max_length))\n",
    "question = np.random.randint(1, question_vocabulary_size,size=(num_samples, max_length))\n",
    "answers = np.random.randint(0, 1,size=(num_samples, answer_vocabulary_size)) # answer id One Hot Encoded"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n",
      "8/8 [==============================] - 1s 78ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 2/10\n",
      "8/8 [==============================] - 1s 79ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 3/10\n",
      "8/8 [==============================] - 1s 76ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 4/10\n",
      "8/8 [==============================] - 1s 70ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 5/10\n",
      "8/8 [==============================] - 1s 73ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 6/10\n",
      "8/8 [==============================] - 1s 76ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 7/10\n",
      "8/8 [==============================] - 1s 80ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 8/10\n",
      "8/8 [==============================] - 1s 72ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 9/10\n",
      "8/8 [==============================] - 1s 71ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 10/10\n",
      "8/8 [==============================] - 1s 76ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x20a5742a070>"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# you can use Fitting using a list of inputs\n",
    "model.fit([text, question], answers, epochs=10, batch_size=128)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Epoch 1/10\n",
      "8/8 [==============================] - 1s 69ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 2/10\n",
      "8/8 [==============================] - 1s 72ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 3/10\n",
      "8/8 [==============================] - 1s 74ms/step - loss: 0.0000e+00 - acc: 0.0000e+00: 0s - loss: 0.0000e+00 - acc: 0.0\n",
      "Epoch 4/10\n",
      "8/8 [==============================] - 1s 70ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 5/10\n",
      "8/8 [==============================] - 1s 69ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 6/10\n",
      "8/8 [==============================] - 1s 70ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 7/10\n",
      "8/8 [==============================] - 1s 71ms/step - loss: 0.0000e+00 - acc: 0.0000e+00: 0s - loss: 0.0000e+00 - acc: 0.0\n",
      "Epoch 8/10\n",
      "8/8 [==============================] - 1s 69ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 9/10\n",
      "8/8 [==============================] - 1s 69ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n",
      "Epoch 10/10\n",
      "8/8 [==============================] - 1s 66ms/step - loss: 0.0000e+00 - acc: 0.0000e+00\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "<tensorflow.python.keras.callbacks.History at 0x20a5a41a340>"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# You can also pass fit as a dictionary (only if inputs are named)\n",
    "model.fit({'text': text, 'question': question}, answers,epochs=10, batch_size=128)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
